
/****************************************************************************
**
** Copyright (C) 2004-2008 VATATA.com . All rights reserved.
**
** This file is the part of the Miniutil Poject of VATATA.com.
** Vatata's miniutil library is lightweight and portable (for linux
** and Windows). The C++ Class Library included Threadpool, Dll danymic loading, 
** General socket application model and tcp server, httpserver/servlet, etc. 
** It is a pratical utility disigned for who don't want learn the Big C++ 
** Developing Platform, such as  Boost or ACE.
**
** This file may be used under the terms of the GNU General Public
** License versions 2.0 or 3.0 as published by the Free Software
** Foundation and appearing in the files LICENSE.GPL2 and LICENSE.GPL3
** included in the packaging of this file.  Alternatively you may (at
** your option) use any later version of the GNU General Public
** License if such license has been publicly approved by VATATA.com.
** (or its successors, if any) and the Miniutil Project Aministrators. 
**
** Please review the following information to ensure GNU General
** Public Licensing requirements will be met:
** http://www.gnu.org/licenses/lgpl.html. If you are unsure which 
** license is appropriate for your use, please review the following 
** information: http://code.google.com/p/miniutil/ or contact 
** http://www.vatata.com.
**
** In addition, as a special exception, VATATA.com, as the sole
** copyright holder for Miniutil Project, grants users of VATATA
** P2P Platform the right to release and package with the related 
** libraries without the source code.
**
** This file is provided "AS IS" with NO WARRANTY OF ANY KIND,
** INCLUDING THE WARRANTIES OF DESIGN, MERCHANTABILITY AND FITNESS FOR
** A PARTICULAR PURPOSE. vatata reserves all rights not expressly
** granted herein.
**
** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
**
****************************************************************************/



#include "miniupnpc.h"
#include "upnpcommands.h"

#include "miniutil/supnpmanager.h"

#include "miniutil/address.h"
#include "miniutil/strutil.h"

namespace miniutil
{
    namespace upnp
    {
		simpleManager::simpleManager(std::string _localip, int _internalTcpPort, int _externalTcpPort, 
			int _internalUdpPort, int _externalUdpPort, int _retryCount ) 
		{
            mapOK = false;
			localIp = _localip;
            internalTcpPort =  _internalTcpPort;
            externalTcpPort =  _externalTcpPort;
            internalUdpPort = _internalUdpPort;
            externalUdpPort = _externalUdpPort;
			retrycount = _retryCount;
			init();
		}

  //      simpleManager::simpleManager(int _internalPort, int _externalPort, int _retryCount ) 
		//{
  //          mapOK = false;
  //          internalTcpPort =  _internalPort;
  //          externalTcpPort =  _externalPort;
  //          internalUdpPort = _internalPort;
  //          externalUdpPort = _externalPort;
		//	if(externalUdpPort != -1)
		//		externalUdpPort = externalTcpPort + 1000;
		//	retrycount = _retryCount;
		//	init();
		//}


		simpleManager::~simpleManager()
		{
			if(mapOK)
			{
				if(externalTcpPort != -1)
					delEntry(externalTcpPort, "TCP");
				if(externalUdpPort != -1)
					delEntry(externalUdpPort, "UDP");
			}
		}

		void simpleManager::init()
		{
			int ret;
			ret = findDevice();
			if(ret == 0)
			{
				if(externalTcpPort != -1)
				{
					//not require delete? will override it
					//delEntry(externalTcpPort, "TCP");
					//delEntry(externalTcpPort, "UDP");
					if(internalTcpPort != -1)
						ret = addEntry(externalTcpPort, internalTcpPort, "TCP");
				}

				if(externalUdpPort != -1)
				{
					//delEntry(externalUdpPort, "TCP");
					//delEntry(externalUdpPort, "UDP");
					if(internalUdpPort != -1)
						ret = addEntry(internalUdpPort, internalUdpPort, "UDP");
				}

				mapOK = true;
			}
		}

		int simpleManager::findDevice()
		{
            struct UPNPDev * devlist = NULL;
			char lanaddr[16]; /* my ip address on the LAN */
            memset(lanaddr, 0x00, sizeof(lanaddr));
			devlist = upnpDiscover(2000, NULL, NULL);
            if(devlist != NULL)
            {
                struct UPNPDev * device;
                struct UPNPUrls urls;
                struct IGDdatas data;

                printf("List of UPNP devices found on the network :\n");
                for(device = devlist; device; device = device->pNext)
                {
                    printf(" desc: %s\n st: %s\n\n",
                    device->descURL, device->st);
                }
                int i = UPNP_GetValidIGD(devlist, &urls, &data, lanaddr, sizeof(lanaddr));
                if(i != 0)
                {
                    //if(i == 1)
                    printf("Found valid IGD : %s\n", urls.controlURL);

					controlURL = urls.controlURL;
					servicetype = data.servicetype;
					FreeUPNPUrls(&urls);
				}
				freeUPNPDevlist(devlist);
				devlist = NULL;
			}
			return 0;
		}

		int simpleManager::addEntry(int extport, int innport, std::string proto)
		{
			if(controlURL.empty())
				return -1;
			int ret;

            static string mappname = "SimpleUpnpManager";
			ret = miniutil::upnp::UPNP_AddPortMapping(controlURL.c_str(),servicetype.c_str(),
				miniutil::util::toString(extport).c_str() , 
				miniutil::util::toString(innport).c_str(), 
				localIp.c_str(), mappname.c_str(), proto.c_str());

			if(ret != UPNPCOMMAND_SUCCESS)
				return -1 ;
			return 0;

		}

		int simpleManager::delEntry(int extport, std::string proto)
		{
			if(controlURL.empty())
				return -1;
			UPNP_DeletePortMapping(controlURL.c_str(), servicetype.c_str(),  
				miniutil::util::toString( extport ).c_str(), proto.c_str());
			return 0;
		}

    }
}